#include <jni.h>
#include <string>
#include "../LogUtil.h"
#include <vector>
#include "Calculator.h"
#include <sstream>   // 用于 std::ostringstream
#include <iomanip>   // 用于 std::fixed 和 std::setprecision


// 实例化计算器对象
Calculator calculator;
std::string result = "";

extern "C"
JNIEXPORT jstring JNICALL
Java_com_binyouwei_ndk_ui_calculator_CalculatorNativeLib_zero(JNIEnv *env, jobject thiz) {
    return env->NewStringUTF(calculator.setNumber("0").c_str());
}

extern "C"
JNIEXPORT jstring JNICALL
Java_com_binyouwei_ndk_ui_calculator_CalculatorNativeLib_one(JNIEnv *env, jobject thiz) {
    return env->NewStringUTF(calculator.setNumber("1").c_str());
}

extern "C"
JNIEXPORT jstring JNICALL
Java_com_binyouwei_ndk_ui_calculator_CalculatorNativeLib_two(JNIEnv *env, jobject thiz) {
    return env->NewStringUTF(calculator.setNumber("2").c_str());
}

extern "C"
JNIEXPORT jstring JNICALL
Java_com_binyouwei_ndk_ui_calculator_CalculatorNativeLib_three(JNIEnv *env, jobject thiz) {
    return env->NewStringUTF(calculator.setNumber("3").c_str());
}

extern "C"
JNIEXPORT jstring JNICALL
Java_com_binyouwei_ndk_ui_calculator_CalculatorNativeLib_four(JNIEnv *env, jobject thiz) {
    return env->NewStringUTF(calculator.setNumber("4").c_str());
}

extern "C"
JNIEXPORT jstring JNICALL
Java_com_binyouwei_ndk_ui_calculator_CalculatorNativeLib_five(JNIEnv *env, jobject thiz) {
    return env->NewStringUTF(calculator.setNumber("5").c_str());
}

extern "C"
JNIEXPORT jstring JNICALL
Java_com_binyouwei_ndk_ui_calculator_CalculatorNativeLib_six(JNIEnv *env, jobject thiz) {
    return env->NewStringUTF(calculator.setNumber("6").c_str());
}

extern "C"
JNIEXPORT jstring JNICALL
Java_com_binyouwei_ndk_ui_calculator_CalculatorNativeLib_seven(JNIEnv *env, jobject thiz) {
    return env->NewStringUTF(calculator.setNumber("7").c_str());
}

extern "C"
JNIEXPORT jstring JNICALL
Java_com_binyouwei_ndk_ui_calculator_CalculatorNativeLib_eight(JNIEnv *env, jobject thiz) {
    return env->NewStringUTF(calculator.setNumber("8").c_str());
}

extern "C"
JNIEXPORT jstring JNICALL
Java_com_binyouwei_ndk_ui_calculator_CalculatorNativeLib_nine(JNIEnv *env, jobject thiz) {
    return env->NewStringUTF(calculator.setNumber("9").c_str());
}

extern "C"
JNIEXPORT jstring JNICALL
Java_com_binyouwei_ndk_ui_calculator_CalculatorNativeLib_percentage(JNIEnv *env, jobject thiz) {
    return env->NewStringUTF(calculator.setNumber("%").c_str());
}

extern "C"
JNIEXPORT jstring JNICALL
Java_com_binyouwei_ndk_ui_calculator_CalculatorNativeLib_decimalPoint(JNIEnv *env, jobject thiz) {
    return env->NewStringUTF(calculator.setNumber(".").c_str());
}

extern "C"
JNIEXPORT jstring JNICALL
Java_com_binyouwei_ndk_ui_calculator_CalculatorNativeLib_add(JNIEnv *env, jobject thiz) {
    return env->NewStringUTF(calculator.setMethod("+").c_str());
}

extern "C"
JNIEXPORT jstring JNICALL
Java_com_binyouwei_ndk_ui_calculator_CalculatorNativeLib_subtract(JNIEnv *env, jobject thiz) {
    return env->NewStringUTF(calculator.setMethod("-").c_str());
}

extern "C"
JNIEXPORT jstring JNICALL
Java_com_binyouwei_ndk_ui_calculator_CalculatorNativeLib_multiplication(JNIEnv *env, jobject thiz) {
    return env->NewStringUTF(calculator.setMethod("×").c_str());
}

extern "C"
JNIEXPORT jstring JNICALL
Java_com_binyouwei_ndk_ui_calculator_CalculatorNativeLib_division(JNIEnv *env, jobject thiz) {
    return env->NewStringUTF(calculator.setMethod("÷").c_str());
}

extern "C"
JNIEXPORT jstring JNICALL
Java_com_binyouwei_ndk_ui_calculator_CalculatorNativeLib_delete(JNIEnv *env, jobject thiz) {
    return env->NewStringUTF(calculator.erasure().c_str());
}

extern "C"
JNIEXPORT jstring JNICALL
Java_com_binyouwei_ndk_ui_calculator_CalculatorNativeLib_equals(JNIEnv *env, jobject thiz) {
    return env->NewStringUTF(calculator.equal().c_str());
}

extern "C"
JNIEXPORT void JNICALL
Java_com_binyouwei_ndk_ui_calculator_CalculatorNativeLib_memoryClear(JNIEnv *env, jobject thiz) {
    calculator.clearMemory();
}

extern "C"
JNIEXPORT void JNICALL
Java_com_binyouwei_ndk_ui_calculator_CalculatorNativeLib_memoryPlus(JNIEnv *env, jobject thiz) {
    calculator.setMemory();
}

extern "C"
JNIEXPORT void JNICALL
Java_com_binyouwei_ndk_ui_calculator_CalculatorNativeLib_memoryMinus(JNIEnv *env, jobject thiz) {
    calculator.backMemory();
}

extern "C"
JNIEXPORT jstring JNICALL
Java_com_binyouwei_ndk_ui_calculator_CalculatorNativeLib_memoryRecall(JNIEnv *env, jobject thiz) {
    return env->NewStringUTF(calculator.totalMemory().c_str());
}

extern "C"
JNIEXPORT jstring JNICALL
Java_com_binyouwei_ndk_ui_calculator_CalculatorNativeLib_clear(JNIEnv *env, jobject thiz) {
    return env->NewStringUTF(calculator.clear().c_str());
}

std::string Calculator::setMethod(std::string method) {
    if (number1.empty()) return "0";
    if (!number1.empty() && !this->method.empty() && !number2.empty()) {
        const std::string &value = equal();
        this->method = method;
        return value + this->method;
    } else if (!number1.empty() && !this->method.empty()) {
        this->method = method;
        return number1 + this->method;
    } else {
        if (number1.back() == '.') {
            number1.pop_back();
            this->method = method;
            return number1 + this->method;
        } else {
            this->method = method;
            return this->number1 + this->method;
        }
    }
}

std::string Calculator::setNumber(std::string digit) {
    if (method.empty()) {
        if (number1 == "0") {
            if (digit == ".")
                this->number1 += digit;
            else this->number1 = digit;
        } else if (number1 == "0" && digit == ".")
            number1 = "0.";
        else number1 += digit;
    } else {
        this->number2 += digit;
    }
    return number1 + method + number2;
}

std::string Calculator::equal() {
    if (number1.empty() || number2.empty() || method.empty()) return number1 + method + number2;
    count();
    method = "";
    number2 = "";
    return number1;
}

std::string Calculator::count() {
    std::string result;
    if (method == "+") {
        double value = std::stod(number1) + std::stod(number2);
        result = changeFormat(value);
    } else if (method == "-") {
        double value = std::stod(number1) - std::stod(number2);
        result = changeFormat(value);
    } else if (method == "×") {
        double value = std::stod(number1) * std::stod(number2);
        result = changeFormat(value);
    } else if (method == "÷") {
        double value = std::stod(number1) / std::stod(number2);
        result = changeFormat(value);
    } else if (method == "%") {
        // stoi 字符串转换成整数
        double value = std::stoi(number1) % std::stoi(number2);
        result = changeFormat(value);
    }
    return result;
}

std::string Calculator::clear() {
    method = "";
    number1 = "";
    number2 = "";
    return "0";
}

std::string Calculator::erasure() {
    if (!number2.empty()) {
        // 删除最后一个元素
        number2.pop_back();
    } else if (!method.empty()) {
        method.pop_back();
    } else if (!number1.empty()) {
        number1.pop_back();
    }
    return number1 + method + number2;
}

void Calculator::setMemory() {
    if (number1.empty()) return;
    else if (!number1.empty() && !method.empty() && !number2.empty()) {
        const std::string &result = count();
        // 给数组添加一个值
        memorys.push_back(result);
    } else {
        // 给数组添加一个值
        memorys.push_back(number1);
    }
}

void Calculator::backMemory() {
    if (memorys.empty()) return;
    // 最后入栈的值退栈
    memorys.pop_back();
}

void Calculator::clearMemory() {
    if (memorys.empty()) return;
    memorys.clear();
}

std::string Calculator::totalMemory() {
    double sum = 0;
    if (memorys.empty()) return number1 + method + number2;
    for (const auto &item: memorys) {
        LOGE("item: %s", item.c_str());
        sum += std::stod(item);
    }
    number1 = changeFormat(sum);
    method = "";
    number2 = "";
    return number1;
}

std::string Calculator::changeFormat(double value) {
    if (value - int(value) == 0)
        return std::to_string(int(value));
    else {
        std::ostringstream out;
        // 保留两位小数
        out << std::fixed << std::setprecision(2) << value;
        return out.str();
    }
}